package com.mdp.tpa.wechat.service;

import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

import com.mdp.tpa.wechat.api.SignService;
import com.mdp.tpa.wechat.api.TicketService;
import com.mdp.tpa.wechat.config.WxpubProperties;
import com.mdp.tpa.wechat.util.RandomUtil;
import com.mdp.tpa.wechat.util.SafeUtil;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * 附录1-JS-SDK使用权限签名算法
 * 当页面需要调用http://res.wx.qq.com/open/js/jweixin-1.0.0.js时，首先需要对页面进行注册，签名验证
 * https://mp.weixin.qq.com/wiki
 * @author cyc
 *
 */
@Service
public class SignServiceImpl implements SignService {
	
	Log log=LogFactory.getLog(SignServiceImpl.class);
	 
	public String appid; 
	
	@Autowired
	WxpubProperties properties;

	
	@Autowired
    TicketService wxApiTicket;
	
	/***
	 * 向微信服务器申请访问jsapi前对参数进行签名
	 * @param url 需要签名到url,不带＃
	 * @return
	 */
	public Map<String,Object> signUrl(String url){
		Map<String,Object> m=new HashMap<String,Object>();
		Date d=new Date();
		String timestamp=(d.getTime()+"").substring(3);
	    String nonceStr= RandomUtil.getRandomStr();
	    String jsapi_ticket=wxApiTicket.getJsapiTicket().getTicket();
	    String string1="jsapi_ticket="+jsapi_ticket+"&noncestr="+nonceStr+"&timestamp="+timestamp+"&url="+url;
	    String signature= SafeUtil.sha1(string1);
	    m.put("appid", properties.getAppid());
		m.put("timestamp", timestamp);
		m.put("nonceStr", nonceStr);
		m.put("signature", signature);
		return m;
	}

	/***
	 * 向微信服务器申请微信支付前对数据进行加密签名
	 * @param  p 需要加密的参数
	 * @param  key 密钥
	 * @return
	 */
	public  String signPayMd5(Map<String,Object> p,String key){
		return signUtilsPayMd5(p,key);
	}
	
	/***
	 * 向微信服务器申请微信支付前对数据进行加密签名
	 * @param  p 需要加密的参数
	 * @param  key 密钥
	 * @return
	 */
	public static String signUtilsPayMd5(Map<String,Object> p,String key){
		Object[] array= (Object[]) p.keySet().toArray();
		Arrays.sort(array);
		String str="";
		int i=0;
		for (Object k : array) {
			Object value=p.get(k);
			if(i>0){
				str=str+"&"+k+"="+value;
			}else{
				str=k+"="+value;
			}
			i++;
			
		}
		str=str+"&key="+key;
	    String signature=SafeUtil.md5(str);
	     
		return signature;
	}
	
	/**
	 *  1.将 api_ticket、timestamp、card_id、code、openid、nonce_str的value值进行字符串的字典序排序。
		2.将所有参数字符串拼接成一个字符串进行sha1加密，得到signature。
		3.signature中的timestamp，nonce字段和card_ext中的timestamp，nonce_str字段必须保持一致。
		4.code=1434008071，timestamp=1404896688，card_id=pjZ8Yt1XGILfi-FUsewpnnolGgZk， api_ticket=ojZ8YtyVyr30HheH3CM73y7h4jJE ，nonce_str=123 则signature=sha1(12314048966881434008071ojZ8YtyVyr30HheH3CM73y7h4jJEpjZ8Yt1XGILfi-FUsewpnnolGgZk)=f137ab68b7f8112d20ee528ab6074564e2796250。
	 * @param cardList
	 * @param openid
	 * @return
	 */
	@Override
	public List<Map<String,Object>> signForAddCard( List<String> cardList,String openid,String outerStr){
		Date d=new Date();
		Long time=d.getTime()/1000;
		Integer timeIn=time.intValue();
		String timeSecond=timeIn.toString();
		String api_ticket=wxApiTicket.getApiTicket().getTicket();
		List<Map<String,Object>> cardListResult=new ArrayList<Map<String,Object>>();
		for (int i = 0; i <cardList.size(); i++) {
			Map<String,Object> m=new HashMap<String,Object>();
			String cardId=cardList.get(i);
			String code=""; 
			String timestamp=timeSecond;
			String fixed_begintimestamp=timeSecond;
			String nonce_str=RandomUtil.getRandomStr(); 
			//api_ticket、timestamp、card_id、code、openid、nonce_str
			String[] array= {api_ticket,timestamp,cardId,nonce_str};
			Arrays.sort(array);
			String str="";
			for (int j = 0; j < array.length; j++) {
				str=str+array[j];
			}
			// SHA1签名生成
			MessageDigest crypt = null;
			try {
				crypt = MessageDigest.getInstance("SHA-1");
				crypt.update(str.getBytes());
			} catch (NoSuchAlgorithmException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
            String signature = byteToHex(crypt.digest());
            
				m.put("timestamp", timestamp);
				m.put("nonce_str", nonce_str);
				m.put("fixed_begintimestamp", fixed_begintimestamp	);
				m.put("outer_str", outerStr);
				m.put("signature", signature);
				
				Map<String,Object> map=new HashMap();
				map.put("cardId", cardId);
				map.put("cardExt", m);
				
				cardListResult.add(map);
		}
		return cardListResult;
	}
	
	 private static String byteToHex(final byte[] hash) {
			StringBuffer hexstr = new StringBuffer();
			String shaHex = "";
			for (int k = 0; k < hash.length; k++) {
				shaHex = Integer.toHexString(hash[k] & 0xFF);
				if (shaHex.length() < 2) {
					hexstr.append(0);
				}
				hexstr.append(shaHex);
			}
			return hexstr.toString();
	    }

	@Override
	public String paySignDesposit(Map<String, String> p, String key) throws UnsupportedEncodingException, NoSuchAlgorithmException, InvalidKeyException {
		// TODO Auto-generated method stub
		  Map<String, String> params = new HashMap<String, String>();
	        Set<String> set = p.keySet();
	        for (String string : set) {
	            if(!p.get(string).equals("")){
	                params.put(string, String.valueOf(p.get(string)));
	            }
	        }
	        String string1 = createSign(params);
	        String stringSignTemp = string1 + "&key=" + key;
	        //return DigestUtils.sha256Hex(stringSignTemp).toUpperCase();
	        Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
	        SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(), "HmacSHA256");
	        sha256_HMAC.init(secret_key);
	        //  utf-8 : 解决中文加密不一致问题,必须指定编码格式
	        return byteArrayToHexString(sha256_HMAC.doFinal(stringSignTemp.getBytes("utf-8"))).toUpperCase();
	}
	 /**
     * 将加密后的字节数组转换成字符串
     *
     * @param b 字节数组
     * @return 字符串
     */
    private static String byteArrayToHexString(byte[] b) {
        StringBuilder hs = new StringBuilder();
        String stmp;
        for (int n = 0; b!=null && n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0XFF);
            if (stmp.length() == 1)
                hs.append('0');
            hs.append(stmp);
        }
        return hs.toString().toLowerCase();
    }
    /**
     * 构造package
     * @param params
     * @return
     * @throws UnsupportedEncodingException
     */
    public  static String createSign(Map<String, String> params) throws UnsupportedEncodingException {
        Set<String> keysSet = params.keySet();
        Object[] keys = keysSet.toArray();
        Arrays.sort(keys);
        StringBuffer temp = new StringBuffer();
        boolean first = true;
        for (Object key : keys) {
            if (first) {
                first = false;
            } else {
                temp.append("&");
            }
            temp.append(key.toString()).append("=");
            Object value = params.get(key);
            String valueString = "";
            if (null != value) {
                valueString = value.toString();
            }
            temp.append(valueString);
        }
        return temp.toString();
    }

}
